package FlowGram.Application.Parser;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import FlowGram.Application.Parser.Actions.*;
import FlowGram.Application.Parser.Actions.Control.FunctionDefinition;
import FlowGram.Application.Parser.Utility.ClassFinder;


/**
 * 
 * @author thackray
 *
 */
public class FinchParser {

	
	protected Class[] actions;
	protected int currentStatement;
	protected String[] statements;
	
	public FinchParser(){
		this.findActions();
	}
	
	
	public FinchProgramFlow Parse(String program) throws FinchParserException{
		this.statements = program.split("\n");
		this.currentStatement = 0;
		
		FinchProgramFlow flow = new FinchProgramFlow();
		try{
			while(this.currentStatement < this.statements.length){
				String statemt = this.statements[this.currentStatement].trim();
				
				/*if(statemt.startsWith("//") || statemt.equals("")){
					this.currentStatement++;
					continue; //comment
				}*/
				
				FinchAction action = null;
				if(this.actions.length > 0){
					for(int j=0; j<this.actions.length; j++){
						try{
							Method m = this.actions[j].getMethod("matches", String.class);
							Boolean success = (Boolean)m.invoke(null, new Object[]{ statemt });
							if(success){
								Constructor c;
								try{
									c = this.actions[j].getConstructor(new Class[]{FinchParser.class});
									action = (FinchAction)c.newInstance(this);
								}catch(NoSuchMethodException e){
									c = this.actions[j].getConstructor(null);
									action = (FinchAction)c.newInstance(null);
								}
								
								//action = (FinchAction)c.newInstance(null);
								break;
							}
						}catch(Exception e){
							throw new FinchParserException("Action '"+this.actions[j].getSimpleName()+"' does not implement the matches method!", this.currentStatement);
						}
					}
				}
				if(action != null){
					action.parse(statemt);
					//if(!(action instanceof FunctionDefinition)){
						flow.enqueueAction(action);
					//}
				}else{
					throw new FinchParserException("Unrecgonized token '"+statemt+"'", this.currentStatement);
				}
				this.currentStatement++;
			}
		}catch(FinchParserException e){
			e.lineNumber = this.currentStatement;
			throw e;
			//return null;
		}
		return flow;
	}
	public String getNextStatement() throws FinchParserException{
		this.currentStatement++;
		if(this.currentStatement >= this.statements.length){
			throw new FinchParserException("Unexpected end of program", this.currentStatement);
		}
		return this.statements[this.currentStatement].trim();
	}
	protected void exceptionThrown(FinchParserException e){
		System.out.println("Parse Error: "+e.getMessage()+" on line "+e.getLineNumber());
		
	}
	
	protected void findActions(){
		this.actions = ClassFinder.findActions();
	}
	
}
